package server

import (
	"errors"
	"fmt"
	"github.com/nntaoli-project/goex"
	"github.com/nntaoli-project/goex/binance"
	"github.com/patrickmn/go-cache"
	"log"
	"net/http"
	"quantization_trading/src/models"
	"quantization_trading/src/mycache"
	"quantization_trading/src/server/ws"
	"quantization_trading/src/util"
	"strings"
	"sync"
	"time"
)
type OrderHandleBack func(order models.Order)
//初始化 ：获取数据库中运行的订单加入缓存中
type OrderServer struct {
	account models.Account
	BinanceSwap *binance.BinanceSwap
	OrderHandleBackMap map[string]OrderHandleBack
	StopC chan bool
}
var lck sync.Mutex


//初始化启动订单
func StartOrder()  {
	accounts := []models.Account{}

	key1 := fmt.Sprintf("%s_user", "hl")
	if x, found := mycache.AccountCache.Get(key1); found {
		accounts = x.([]models.Account)
		for _,ac := range accounts{
			orderMap := make(map[string]*models.Order)
			os := NewOrderServer(ac)
			go os.SubOrderWs()
			mycache.OrderServerCache.Set(ac.AccountName,os,cache.NoExpiration)
			order_list, err := models.FindAllUseOrder(ac.AccountName)
			if err != nil{
				OrderLog.Error(err)
			}else {
				for _,order := range order_list{
					or :=order
					orderMap[order.Cid] = &or
				}
				mycache.OrderCache.Set(ac.AccountName,orderMap,cache.NoExpiration)
			}
		}
	}
}

func NewOrderServer(ac models.Account) OrderServer {
	var baDapi = binance.NewBinanceSwap(&goex.APIConfig{
		HttpClient:   http.DefaultClient,
		ApiKey:       ac.ApiKey,
		ApiSecretKey: ac.SecretKey,
	})
	return OrderServer{
		account: ac,
		BinanceSwap: baDapi,
		OrderHandleBackMap: make(map[string]OrderHandleBack),
		StopC:make(chan bool),
	}

}
//限价
func (os *OrderServer)LimitOrder(currencyPair string, price, amount string,openType int, opt ...string)(*models.Order) {
	currencys := strings.Split(currencyPair,"_")
	currencyA :=goex.NewCurrency(currencys[0],"")
	currencyB :=goex.NewCurrency(currencys[1],"")
	Pair := goex.NewCurrencyPair(currencyA,currencyB)
	OrderLog.Infof("发送限价委托%s,价格：%s,数量：%s，委托类型%d",currencyPair,price,amount,openType)
	FutureOrder,err :=os.BinanceSwap.LimitFuturesOrder(Pair, goex.SWAP_USDT_CONTRACT, price, amount, openType,goex.Futures_Twoway_Position_Mode)
	if err !=nil{
		OrderLog.Error(err)
		return nil
	}

	// 1。查询缓存订单
	var order_list map[string]*models.Order
	var or *models.Order
	if x ,fund :=mycache.OrderCache.Get(os.account.AccountName) ;fund {
		order_list = x.(map[string]*models.Order)
	}
	if x,ok :=order_list[FutureOrder.ClientOid];ok{
		or = x
	}else {
		or = &models.Order{
			Cid: FutureOrder.ClientOid,
			ExecutedQty: FutureOrder.DealAmount,
			OrderId: FutureOrder.OrderID2,
			AvgPrice: FutureOrder.AvgPrice,
			OrigQty: FutureOrder.Amount,
			Price: FutureOrder.Price,
			OType: FutureOrder.OType,
			Type: FutureOrder.AlgoType,
			Symbol: currencyPair,
			UpdateTime: time.Now().Unix(),
			StatusUse: true,
		}
	}
	os.SaveOrder(or)
	return or
}

//市价
func (os *OrderServer)MarketOrder(currencyPair string,  amount string,openType int, opt ...string)(*models.Order) {
	tempA,tempB := util.PairChangeCurrency(currencyPair)
	currencyA :=goex.NewCurrency(tempA,"")
	currencyB :=goex.NewCurrency(tempB,"")
	Pair := goex.NewCurrencyPair(currencyA,currencyB)
	OrderLog.Infof("发送市价委托%s,数量：%s，委托类型%d",currencyPair,amount,openType)
	FutureOrder,err :=os.BinanceSwap.PlaceFutureOrder2(Pair, goex.SWAP_USDT_CONTRACT, "0", amount, openType, 1,"",goex.Futures_Twoway_Position_Mode)
	if err !=nil{
		OrderLog.Error(err)
		return nil
	}
	// 1。查询缓存订单
	var order_list map[string]*models.Order
	var or *models.Order
	if x ,fund :=mycache.OrderCache.Get(os.account.AccountName) ;fund {
		order_list = x.(map[string]*models.Order)
	}
	if x,ok :=order_list[FutureOrder.ClientOid];ok{
		or = x
	}else {
		or = &models.Order{
			Cid: FutureOrder.ClientOid,
			ExecutedQty: FutureOrder.DealAmount,
			OrderId: FutureOrder.OrderID2,
			AvgPrice: FutureOrder.AvgPrice,
			OrigQty: FutureOrder.Amount,
			Price: FutureOrder.Price,
			OType: FutureOrder.OType,
			Type: FutureOrder.AlgoType,
			Symbol: currencyPair,
			UpdateTime: time.Now().Unix(),
			StatusUse: true,
		}
	}
	os.SaveOrder(or)
	return or
}

// 限价全平仓(账号级别)
func (os *OrderServer)LimitOrderAllClose(currencyPair string, price string) (int,error) {
	api_pair := strings.ToLower(strings.ReplaceAll(currencyPair,"_",""))
	var order_list map[string]*models.Order
	var err_msg string
	var temp_order []*models.Order
	if x ,fund :=mycache.OrderCache.Get(os.account.AccountName) ;fund{
		order_list = x.(map[string]*models.Order)
		// 遍历该账号所有订单，如果有平仓单全部取消
		for _,order := range order_list{
			if (order.OType == goex.CLOSE_BUY || order.OType == goex.CLOSE_SELL) {
				if  api_pair == strings.ToLower(order.Symbol) {
					os.CancelOrder(currencyPair,order.Cid)
				}
			}else {
				if  api_pair == strings.ToLower(order.Symbol) {
					temp_order = append(temp_order, order)
				}
			}
		}
		// 发送平仓单
		for _,order :=range temp_order{
			if order.OType == goex.OPEN_BUY {
				is_flag := os.LimitOrder(currencyPair,price,goex.FloatToString(order.ExecutedQty,10),goex.CLOSE_BUY,order.Cid)
				if is_flag == nil{
					err_msg += fmt.Sprintf("发送限价订单失败,交易对为：%s，价格为：%s,数量为：%f\n",currencyPair,price,order.ExecutedQty)
				}
			}else if order.OType == goex.OPEN_SELL {
				is_flag := os.LimitOrder(currencyPair,price,goex.FloatToString(order.ExecutedQty,10),goex.CLOSE_SELL,order.Cid)
				if is_flag ==nil{
					err_msg += fmt.Sprintf("发送限价订单失败,交易对为：%s，价格为：%s,数量为：%f\n",currencyPair,price,order.ExecutedQty)
				}
			}
		}
	}
	if err_msg != ""{
		return util.LIMIT_CLOSE_ALL_ORDER_ERROR,errors.New(err_msg)
	}else {
		return util.LIMIT_CLOSE_ALL_ORDER_SUSSESS,nil
	}
}

// 限价全市价格
func (os *OrderServer)MarketOrderAllClose(currencyPair string) (int,error) {
	api_pair := strings.ToLower(strings.ReplaceAll(currencyPair,"_",""))
	var err_msg string
	var temp_order []*models.Order
	var order_list map[string]*models.Order
	if x ,fund :=mycache.OrderCache.Get(os.account.AccountName) ;fund {
		order_list = x.(map[string]*models.Order)
		// 遍历该账号所有订单，如果有平仓单全部取消
		for _,order := range order_list{
			if (order.OType == goex.CLOSE_BUY || order.OType == goex.CLOSE_SELL) {
				if  api_pair == strings.ToLower(order.Symbol) {
					os.CancelOrder(currencyPair,order.Cid)
				}
			}else {
				if  api_pair == strings.ToLower(order.Symbol) {
					temp_order = append(temp_order, order)
				}
			}
		}
		// 发送平仓单
		for _,order :=range temp_order{
			if order.OType == goex.OPEN_BUY {
				is_flag := os.MarketOrder(currencyPair,goex.FloatToString(order.ExecutedQty,10),goex.CLOSE_BUY,order.Cid)
				if is_flag == nil{
					err_msg += fmt.Sprintf("发送市价订单失败,交易对为：%s，数量为：%f\n",currencyPair,order.ExecutedQty)
				}
			}else if order.OType == goex.OPEN_SELL {
				is_flag := os.MarketOrder(currencyPair,goex.FloatToString(order.ExecutedQty,10),goex.CLOSE_SELL,order.Cid)
				if is_flag == nil{
					err_msg += fmt.Sprintf("发送市价订单失败,交易对为：%s，数量为：%f\n",currencyPair,order.ExecutedQty)
				}
			}
		}
	}
	if err_msg != ""{
		return util.MARKET_CLOSE_ALL_ORDER_ERROR,errors.New(err_msg)
	}else {
		return util.MARKET_CLOSE_ALL_ORDER_SUSSESS,nil
	}

}

//取消订单
func (os *OrderServer)CancelOrder(currencyPair string, cId string) (bool) {
	tempA,tempB := util.PairChangeCurrency(currencyPair)
	currencyA :=goex.NewCurrency(tempA,"")
	currencyB :=goex.NewCurrency(tempB,"")
	Pair := goex.NewCurrencyPair(currencyA,currencyB)
	OrderLog.Infof("取消订单%s,订单编号：%s",currencyPair,cId)
	b, err :=os.BinanceSwap.FutureCancelOrder(Pair,goex.SWAP_USDT_CONTRACT,cId)
	if err != nil{
		log.Println(err)
	}
	return b
}

//更新订单（缓存+数据）
func (os *OrderServer)SaveOrder(od *models.Order)  {
	lck.Lock()
	var order_list map[string]*models.Order
	if x ,fund :=mycache.OrderCache.Get(od.AccountName) ;fund{
		order_list = x.(map[string]*models.Order)
	}

	// 保存缓存
	if len(order_list) >0 {
		order_list[od.Cid] = od
	}else {
		order_list = make(map[string]*models.Order)
		order_list[od.Cid] = od
	}

	if !od.StatusUse {
		delete(order_list,od.Cid)
	}
	mycache.OrderCache.Set(od.AccountName,order_list,cache.NoExpiration)
	// 保存数据库
    if oOrder :=models.FindOrder(od.Cid);oOrder != nil{
		models.UpdateOrder2(oOrder,od)
	} else {
		models.AddOrder(od)
	}
	lck.Unlock()
	for _,orderHandleBack := range os.OrderHandleBackMap{
		orderHandleBack(*od)
	}
}

//订阅订单ws
func (os *OrderServer)SubOrderWs()  {
	sub :=ws.NewSubOrder(os.account.Exchange,goex.SWAP_USDT_CONTRACT,os.account.ApiKey,"","")
	sub.SubscribeOrder()
	t := time.NewTicker(time.Second * 10)
	defer t.Stop()
	for  {
		select {
		case o :=<-sub.Order:
			o.AccountName = os.account.AccountName
			go os.SaveOrder(&o)
		case <-t.C:
			os.SynchronousOrder()
		case <-os.StopC:
			OrderLog.Infoln("退出价订单订阅")
			return
		}
	}
}


//func (os *OrderServer)SynchronousOrder(){
//	log.Println("同步委托")
//	var strategy_list map[string]*models.Strategy
//	strategy_map := make(map[string][]string,10)
//
//	if x ,fund :=mycache.StrategyCache.Get(os.account.AccountName) ;fund{
//		strategy_list = x.(map[string]*models.Strategy)
//
//		//给零时map赋值 如：{"BTCUSDT"：【"123"，"4512343"，"dsfdsa"】}
//		for _,strategy :=range strategy_list{
//
//			if symbol_list_temp,ok :=strategy_map[os.account.AccountName];ok{
//				symbol_list_temp = append(symbol_list_temp,strategy.Symbol)
//				strategy_map[os.account.AccountName] = symbol_list_temp
//			}else {
//				symbol_list_temp = []string{strategy.Symbol}
//				strategy_map[os.account.AccountName] = symbol_list_temp
//			}
//		}
//
//		// 遍历map更新订单
//		for _,v :=range strategy_map[os.account.AccountName]{
//			var currencyA,currencyB goex.Currency
//			v = strings.ToUpper(strings.ReplaceAll(v,"_",""))
//			if find := strings.Contains(v, "USDT"); find {
//				currencyA = goex.NewCurrency(strings.ReplaceAll(v,"USDT",""),"")
//				currencyB = goex.NewCurrency("USDT","")
//			}else {
//				currencyA = goex.NewCurrency(strings.ReplaceAll(v,"USD",""),"")
//				currencyB = goex.NewCurrency("USD","")
//			}
//			Pair := goex.NewCurrencyPair(currencyA,currencyB)
//			newTime := time.Now().UnixNano() / 1e6
//			startTime := newTime - 60*60*24*1000
//			parm := make(map[string]interface{})
//			parm["startTime"] = startTime
//			forder,err := os.BinanceSwap.GetOrderHistorys(Pair,parm)
//			if err !=nil{
//				log.Println(err)
//			}else {
//				for _,f_order :=range forder{
//					or := &models.Order{
//						Cid: f_order.Cid,
//						ExecutedQty: f_order.DealAmount,
//						OrderId: f_order.OrderID2,
//						AvgPrice: f_order.AvgPrice,
//						OrigQty: f_order.Amount,
//						Price: f_order.Price,
//						Symbol: f_order.Currency.String(),
//						UpdateTime: time.Now().Unix(),
//						StatusUse: true,
//					}
//					if f_order.PositionSide == goex.LONG && f_order.Side ==util.BUY{
//						or.OType = util.OPEN_BUY
//					}else if f_order.PositionSide == goex.SHORT && f_order.Side ==util.BUY{
//						or.OType = util.OPEN_SELL
//					}else if  f_order.PositionSide == goex.LONG && f_order.Side ==util.SELL {
//						or.OType = util.CLOSE_BUY
//					}else {
//						or.OType = util.CLOSE_SELL
//					}
//					or.Type = util.MARKET
//					if f_order.Type == "limit"{
//						or.Type = util.LIMIT
//					}
//
//					if or.ExecutedQty == 0 {
//						or.Status = util.NOT_DONE
//					}else if or.ExecutedQty < or.OrigQty{
//						or.Status = util.SOME_DONE
//					}else {
//						or.Status = util.OVER_DONE
//						if or.OType == util.CLOSE_BUY || or.OType == util.CLOSE_SELL {
//							or.StatusUse = false
//						}
//					}
//					os.SaveOrder(or)
//				}
//			}
//		}
//	}
//}

// 同步委托（只更新缓存里的数据）
func (os *OrderServer)SynchronousOrder(){
	log.Println("同步委托")
	var order_list map[string]*models.Order
	order_map := make(map[string][]string,10)
	if x ,fund :=mycache.OrderCache.Get(os.account.AccountName) ;fund{
		order_list = x.(map[string]*models.Order)

		//给零时map赋值 如：{"BTCUSDT"：【"123"，"4512343"，"dsfdsa"】}
		for _,or1 :=range order_list{
			if or_list_temp,ok :=order_map[or1.Symbol];ok{
				if or1.ExecutedQty != or1.OrigQty {
					or_list_temp = append(or_list_temp,or1.OrderId)
					order_map[or1.Symbol] = or_list_temp
				}

			}else {
				if or1.ExecutedQty != or1.OrigQty {
					or_list_temp = append(or_list_temp, or1.OrderId)
					order_map[or1.Symbol] = or_list_temp
				}
			}
		}

		// 遍历map更新订单
		for k,v_order_list :=range order_map{
			var currencyA,currencyB goex.Currency
			var contractType string
			k = strings.ToUpper(strings.ReplaceAll(k,"_",""))
			if find := strings.Contains(k, "USDT"); find {
				currencyA = goex.NewCurrency(strings.ReplaceAll(k,"USDT",""),"")
				currencyB = goex.NewCurrency("USDT","")
				contractType = goex.SWAP_USDT_CONTRACT
			}else {
				currencyA = goex.NewCurrency(strings.ReplaceAll(k,"USD",""),"")
				currencyB = goex.NewCurrency("USD","")
				contractType = goex.SWAP_CONTRACT
			}
			Pair := goex.NewCurrencyPair(currencyA,currencyB)

			forder,err := os.BinanceSwap.GetFutureOrders(v_order_list,Pair,contractType)

			if err !=nil{
				log.Println(err)
			}else {
				for _,f_order :=range forder{
					for _,old_order :=range order_list{
						if old_order.OrderId == f_order.OrderID2{
							// 需要同步的字段
							if old_order.ExecutedQty != f_order.DealAmount{
								old_order.ExecutedQty = f_order.DealAmount
								if old_order.ExecutedQty == 0 {
									old_order.Status = util.NOT_DONE
								}else if old_order.ExecutedQty < old_order.OrigQty{
									old_order.Status = util.SOME_DONE
								}else {
									old_order.Status = util.OVER_DONE
									if old_order.OType == util.CLOSE_BUY || old_order.OType == util.CLOSE_SELL {
										old_order.StatusUse = false
									}
								}
								os.SaveOrder(old_order)
							}
							if f_order.Status == goex.ORDER_CANCEL || f_order.Status == goex.ORDER_CANCEL_ING || f_order.Status == goex.ORDER_REJECT || f_order.Status == goex.ORDER_FAIL{
								old_order.StatusUse = false
								os.SaveOrder(old_order)
							}
						}
					}
				}
			}
		}
	}
}

//添加订阅
func (os *OrderServer)AddSubOrderServer(strategyKey string,f OrderHandleBack)  {
	os.OrderHandleBackMap[strategyKey] = f
}

//删除订阅
func (os *OrderServer)DelSubOrderServer(strategyKey string)  {
	delete(os.OrderHandleBackMap, strategyKey)
}

//市价平，没成交就撤回，成交就发平仓
func (os *OrderServer)MarketOrderClose(cId string)(*models.Order){

	if cId != ""{
		var order_list map[string]*models.Order
		var or *models.Order
		if x ,fund :=mycache.OrderCache.Get(os.account.AccountName) ;fund {
			order_list = x.(map[string]*models.Order)
		}
		if x,ok :=order_list[cId];ok{
			or = x
		}else {
			or = models.FindOrder(cId)
		}
		if or.ExecutedQty == 0 {
			os.CancelOrder(or.Symbol,or.Cid)
			or.StatusUse =false
			os.SaveOrder(or)
			return nil
		}else {
			if or.OType == util.OPEN_BUY || or.OType == util.OPEN_SELL{
				ot := util.CLOSE_BUY
				if or.OType == util.OPEN_SELL{
					ot = util.CLOSE_SELL
				}
				or.StatusUse =false
				os.SaveOrder(or)
				return os.MarketOrder(or.Symbol,goex.FloatToString(or.OrigQty,10),ot)
			}
		}
	}
	return nil
}


//todo 限价平订单，没成交就撤回，成交就限价平